package indi.mozping.echo.server;

import indi.mozping.channelinitializer.MyChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.internal.logging.InternalLogLevel;

import java.net.InetSocketAddress;

/**
 * @author by mozping
 * @Classname EchoServer
 * @Description EchoServer是Netty服务端的引导服务器
 * <p>
 * 监听和接收进来的连接请求
 * 配置Channel来通知一个关于入站消息的EchoServerHandler 实例
 * <p>
 * <p>
 * 服务器的主代码组件是：
 * 1.EchoServerHandler 实现了的业务逻辑，2.通过引导了服务器启动
 * <p>
 * 引导服务器需要执行的步骤是：
 * 1.创建 ServerBootstrap 实例来引导服务器并随后绑定
 * 2.创建并分配一个 NioEventLoopGroup 实例来处理事件的处理，如接受新的连接和读/写数据。
 * 3.指定通道类型是NIO
 * 4.指定本地 InetSocketAddress 给服务器绑定
 * 5.通过 EchoServerHandler实例给每一个新的Channel初始化
 * 6.最后调用 ServerBootstrap.bind() 绑定服务器
 * @Date 2019/9/11 19:24
 */
public class EchoServer {

    private static final int PORT = 12345;

    public static void main(String[] args) throws Exception {
        EchoServer.start();
    }

    private static void start() throws Exception {
        //1.创建EventLoopGroup,
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            //2.创建 ServerBootstrap
            ServerBootstrap b = new ServerBootstrap();
            //3.指定NioEventLoopGroup接受和处理新连接
            b.group(group)
                    //5.设置通道类型，指定使用NIO的传输Channel
                    .channel(NioServerSocketChannel.class)
                    //6.设置socket地址使用所选的端口，服务器将监听该地址端口
                    .localAddress(new InetSocketAddress(PORT))
                    //7.添加EchoServerHandler到Channel的ChannelPipeline
                    //这里的含义是：每当接受一个新的连接，一个子Channel将会被创建，ChannelInitializer
                    //会添加我们的EchoServerHandler实例到Channel的ChannelPipeline。如果有入站信息，这个处理器将被通知。
                    .childHandler(new MyChannelInitializer());
            //8.绑定的服务器;sync同步方式会阻塞当前线程
            ChannelFuture f = b.bind().sync();
            //System.out.println(EchoServer.class.getName() + " started and listen on " + f.channel().localAddress());
            //9.关闭 channel,直到它被关闭,sync同步方式会阻塞当前线程
            f.channel().closeFuture().sync();
        } finally {
            //10.关闭 EventLoopGroup，释放所有资源。
            group.shutdownGracefully().sync();
        }
    }
}